/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.jesseenglish.swingftfy.extensions;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.font.TextAttribute;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

/**
 *
 * @author jesse
 */
public class FTree extends JTree implements MouseListener {

    public FTree() {
        this.setCellRenderer(new IconNodeRenderer());
        this.addMouseListener(this);
    }
    
    public void setBackgroundSelectionColor(Color color) {
        ((IconNodeRenderer)this.getCellRenderer()).setBackgroundSelectionColor(color);
        this.validate();
        this.repaint();
    }
    
    private FNode getNodeAtMouseEventLocation(MouseEvent me) {
        int x = (int) me.getPoint().getX();
        int y = (int) me.getPoint().getY();
        TreePath path = this.getPathForLocation(x, y);
        if (path != null) {
            return (FNode)path.getLastPathComponent();
        }
        return null;
    }
    
    private TreePath getTreePathAtMouseEventLocation(MouseEvent me) {
        int x = (int) me.getPoint().getX();
        int y = (int) me.getPoint().getY();
        TreePath path = this.getPathForLocation(x, y);
        return path;
    }

    public void mouseClicked(MouseEvent me) {
        FNode node = getNodeAtMouseEventLocation(me);
        if (node != null) {
            this.setSelectionPath(getTreePathAtMouseEventLocation(me));
            node.mouseClicked(me);
        } else {
            this.setSelectionPath(null);
        }
    }

    public void mousePressed(MouseEvent me) {
        FNode node = getNodeAtMouseEventLocation(me);
        if (node != null) {
            this.setSelectionPath(getTreePathAtMouseEventLocation(me));
            node.mousePressed(me);
        } else {
            this.setSelectionPath(null);
        }
    }

    public void mouseReleased(MouseEvent me) {
        FNode node = getNodeAtMouseEventLocation(me);
        if (node != null) {
            this.setSelectionPath(getTreePathAtMouseEventLocation(me));
            node.mouseReleased(me);
        } else {
            this.setSelectionPath(null);
        }
    }

    public void mouseEntered(MouseEvent me) {
        FNode node = getNodeAtMouseEventLocation(me);
        if (node != null) {
            node.mouseEntered(me);
        }
    }

    public void mouseExited(MouseEvent me) {
        FNode node = getNodeAtMouseEventLocation(me);
        if (node != null) {
            node.mouseExited(me);
        }
    }
    
    public TreePath getPath(TreeNode node) {
        List list = new ArrayList();

        // Add all nodes to list
        while (node != null) {
            list.add(node);
            node = node.getParent();
        }
        Collections.reverse(list);

        // Convert array of nodes to TreePath
        return new TreePath(list.toArray());
    }
    
    public void expandNode(TreeNode node) {
        TreePath path = getPath(node);

        int row = getRowForPath(path);
        expandRow(row);

        this.validate();
        this.repaint();
    }
    
    public void expandAll(boolean expand) {
        TreeNode root = (TreeNode)this.getModel().getRoot();
    
        // Traverse tree from root
        expandAll(new TreePath(root), expand);
    }
    private void expandAll(TreePath parent, boolean expand) {
        // Traverse children
        TreeNode node = (TreeNode)parent.getLastPathComponent();
        if (node.getChildCount() >= 0) {
            for (java.util.Enumeration e=node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode)e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                expandAll(path, expand);
            }
        }
    
        // Expansion or collapse must be done bottom-up
        if (expand) {
            this.expandPath(parent);
        } else {
            this.collapsePath(parent);
        }
    }
    
    private class IconNodeRenderer extends DefaultTreeCellRenderer {

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
                boolean sel, boolean expanded, boolean leaf, int row,
                boolean hasFocus) {

            JLabel cell = (JLabel)super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
            cell.setOpaque(false);
            cell.setFont(new Font("Lucida Grande", Font.PLAIN, 12));

            if (value instanceof FNode) {
                Icon icon = ((FNode) value).getIcon();
                Map<TextAttribute, Object> textAttributes = ((FNode) value).getTextAttributes();

                if (icon != null) {
                    cell.setIcon(icon);
                }

                if (textAttributes != null) {
                    cell.setFont(cell.getFont().deriveFont(textAttributes));
                }
            }

            return cell;
        }
    }
}
